#include "tini.h"
#include <mbstring.h>
#include <stdio.h>
#include "tapi32ex.h"

TIniSection::TIniSection() 
: TListObj()
, TList(), 
_name( NULL ){}

TIniSection::~TIniSection()
{
	free( _name );
	TIniKey* key = (TIniKey*)TopObj();
	while( key )
	{
		DelObj( key );
		delete key;
		key = (TIniKey*)TopObj();
	}
}

void TIniSection::Set( const char* name )
{
	if( name )
	{
		free( _name );
		_name = _strdup( name );
	}
}

TIniKey* TIniSection::SearchKey( const char* keyName )
{
	TIniKey* key = (TIniKey*)TopObj();
	while( key )
	{
		if( key->GetKey() && _stricmp( keyName, key->GetKey() ) == 0 )
			return key;
		key = (TIniKey*)NextObj( key );
	}
	return NULL;
}

bool TIniSection::AddKey( const char* keyName, const char* value )
{
	TIniKey* key = keyName ? SearchKey( keyName ) : NULL;
	if( key == NULL )
	{
		key = new TIniKey( keyName, value );
		AddObj( key );
	}
	else key->Set( NULL, value );
	return true;
}

bool TIniSection::DelKey( const char* keyName )
{
	TIniKey* key = SearchKey( keyName );
	if( !key )
		return false;
	DelObj( key );
	delete key;
	return true;
}

//////////////////////////////////////////////////////////////////////////
TIniFile::TIniFile( const char* fileName )
: TList()
, _iniFileName( NULL )
, _iniSize( -1 )
, _curSection( NULL )
, _rootSectin( NULL )
{
	Init( fileName );
}
TIniFile::~TIniFile()
{
	free( _iniFileName );
	if( _hMutex ) ::CloseHandle( _hMutex );
}

void TIniFile::Init( const char* fileName )
{
	if( fileName ) _iniFileName = _strdup( fileName );
}

void TIniFile::UnInit()
{
	TIniSection* sec = (TIniSection*)TopObj();
	while( sec )
	{
		DelObj( sec );
		delete sec;
		sec = (TIniSection*)TopObj();
	}
	_rootSectin = NULL;
}

void TIniFile::SetSection( const char* section )
{
	if( _curSection && _curSection != _rootSectin && !_curSection->TopObj() )
	{
		DelObj( _curSection );
		delete _curSection;
	}

	_curSection = SearchSection( section );
	if( _curSection == NULL )
	{
		_curSection = new TIniSection();
		_curSection->Set( section );
		AddObj( _curSection );
	}

}

bool TIniFile::DelSection( const char* section )
{
	TIniSection* sec = SearchSection( section );
	if( !sec ) return false;
	DelObj( sec );
	delete sec;
	if( sec == _curSection ) _curSection = NULL;
	return true;
}

bool TIniFile::DelKey( const char* keyName )
{
	return _curSection ? _curSection->DelKey( keyName ) : false;
}

bool TIniFile::StartUpdate()
{
	return true;
}
bool TIniFile::EndUpdate()
{
	return WriteIni();
}

bool TIniFile::SetStr( const char* keyName, const char* value )
{
	if( !value ) return DelKey( keyName );
	return _curSection ? _curSection->AddKey( keyName, value ) : false;
}

DWORD TIniFile::GetStr( const char* keyName, char* value, int maxSize, const char* defaultValue )
{
	TIniKey* key = _curSection ? _curSection->SearchKey( keyName ) : NULL;
	return sprintf_s( value, maxSize, "%.*s", maxSize, key ? key->GetValue() : defaultValue );
}

bool TIniFile::SetInt( const char* keyName, int value )
{
	char buf[100] = {0};
	sprintf_s( buf,  100, "%d", value );
	return SetStr( keyName, buf );
}

int TIniFile::GetInt( const char* keyName, int defaultValue )
{
	char buf[100] = {0};
	if( GetStr( keyName, buf, sizeof( buf ), "" ) <= 0 )
		return defaultValue;
	return atoi(buf);
}

BOOL TIniFile::Lock()
{
	if( !_hMutex )
	{
		char  buf[1024] ={0};
		char* key = (char*)_mbsrchr( (u_char*)_iniFileName, '\\' );
		key = key ? key + 1 : _iniFileName;

		sprintf_s( buf, 1024, "%s_%x", key, MakeHash( _iniFileName, strlen(_iniFileName), 0 ) );
		_hMutex = ::CreateMutex( NULL, FALSE, buf );
		if( _hMutex == NULL )
			return false;
	}
	return ::WaitForSingleObject( _hMutex, INFINITE );
}

void TIniFile::Unlock()
{
	if( _hMutex )
		ReleaseMutex( _hMutex );
}

TIniSection* TIniFile::SearchSection( const char* section )
{
	TIniSection* sec = _rootSectin;
	while( sec )
	{
		if( sec->GetName() && _stricmp( sec->GetName(), section ) == 0 )
			return sec;
		sec = (TIniSection*)NextObj( sec );
	}
	return NULL;
}

bool TIniFile::WriteIni()
{
	Lock();

	bool ret = false;

	FILE* fp = NULL;
	if( 0 == fopen_s( &fp, _iniFileName, "w" ) )
	{
		for( TIniSection* sec = (TIniSection*)TopObj(); sec; sec = (TIniSection*)NextObj(sec) )
		{
			TIniKey* key = (TIniKey*)sec->TopObj();
			if( key )
			{
				if( sec->GetName() )
					if( fprintf( fp, "[%s]\n", sec->GetName() ) < 0 ) goto END;
				while( key )
				{
					if( key->GetKey() )
					{	
						if( fprintf( fp, "%s=\"%s\"\n", key->GetKey(), key->GetValue() ) < 0 ) 
							goto END;
					}
					else
					{
						if( fprintf( fp, "%s", key->GetValue() ) < 0 )
							goto END;
					}
					key = (TIniKey*)sec->NextObj( key );
				}

			}
		}
END:
		fclose( fp );
	}
	Unlock();
	return ret;
}
